home *** CD-ROM | disk | FTP | other *** search
- ;DOSTSR16.ASM
- ;This is a skeleton DOS TSR, that hooks INT-16h.
- ;All it does is detect a hot key (<alt-z>) and then activates.
- ;Upon activation it accepts further keyboard input and displays
- ;characters on the screen. Another <alt-z> will deactivate the TSR.
- ;Shows how to safely synchronise a TSR with DOS.
- ;Note that the only reason I put ".286" directive in is because I
- ;have used the PUSHA and POPA instructions.
-
- ;...................................................
- .286
- int16 SEGMENT BYTE PUBLIC 'CODE'
- ASSUME cs:int16,ds:int16
- ORG 100h
- install: jmp start
- oldoffivt2F DW 0 ;save old int-2F vector here.
- oldsegivt2F DW 0 ; /
- winloaded DB 0 ;set when Windows is loaded, & viceversa.
- winmode DB 0 ;bit-0=1 if Standard, =0 if Enhanced.
- oldoffivt16 DW 0 ;save old keyboard vector here.
- oldsegivt16 DW 0 ; /
- oldoffivt28 DW 0 ;old int-28h
- oldsegivt28 DW 0 ; /
- tsrpspseg DW 0 ;seg addr of psp, this tsr.
- dosbusyoff DW 0 ;far addr of dos busy flag
- dosbusyseg DW 0 ; /
- isrbusy DB 0 ;set if this isr already in use.
- isrwanted DB 0 ;set=isr tried to start but indos stopped it
- oldpspseg DW 0 ;seg addr of psp prior to interrupt.
- oldsp DW 0 ;stack prior to interrupt.
- oldss Dw 0 ; /
- oldctrlc DB 0 ;ctrl-c on/off
- oldoffivt1B DW 0 ;old vectors
- oldsegivt1B DW 0 ; /
- oldoffivt23 DW 0 ; /
- oldsegivt23 DW 0 ; /
- oldoffivt24 DW 0 ; /
- oldsegivt24 DW 0 ; /
- localstack DB 511 DUP(0)
- localendstack DW 0 ;top of stack
- ;....................................................................
- runtime16:
- ;this is now the "signaller". it is entered at every keypress...
- ;but only when in a DOS VM or in standard real-mode...
- ;
- ;this is particular to int-16h (test if reading a char)....
- cmp ah,0
- je firsthurdle
- cmp ah,10h
- je firsthurdle
- chain: jmp DWORD PTR cs:oldoffivt16 ;chain to old int-16
- ;
- firsthurdle:
- ;give some thought to reentrancy... avoid potential problems with a flag...
- cmp cs:isrbusy,0
- jne chain ;this isr already in use!
- secondhurdle:
- ;now test for the hot-key...
- pushf
- call DWORD PTR cs:oldoffivt16 ;call old int-16.
- cmp ax,2C00h ;<alt-z>
- je thirdhurdle
- iret
- thirdhurdle:
- mov cs:isrwanted,1 ;to tell int-28 that we want to popup.
- ;before doing anything, we need to synchronise with dos...
- ;however the test for the "indos" flag does not work when COMMAND.COM
- ;is running... int-16 called with indos set....
- push ax
- push bx
- push es
- les bx,DWORD PTR cs:dosbusyoff
- mov al,es:[bx] ;get dos-busy flag
- or al,al
- pop es
- pop bx
- pop ax
- jnz chain ;get out, as dos is busy.
- ;
- vvv: mov cs:isrbusy,1 ;lay claim to this isr.
- mov cs:isrwanted,0 ;clear this, since we're in.
- zzz: sti ;now allow interrupts.
- ;(note that if this was a hardware interrupt, would need EOI here also).
- nop
- ;now get the regs setup for the isr... let's use a local stack...
- cli
- mov cs:oldss,ss
- mov cs:oldsp,sp
- mov ss,cs:tsrpspseg ;can do this since es=cs=ds at install.
- mov sp,OFFSET cs:localendstack
- sti
- push es ;save working registers
- push ds ; /
- pusha ; /
- push cs ;set ds == cs
- pop ds ; /
- ;get the seg addr of the old psp (of program prior to interrupt)...
- mov ah,62h
- int 21h ;-->bx
- mov oldpspseg,bx
- ;set dos to use psp of this tsr...
- mov bx,tsrpspseg ;(saved during install)
- mov ah,50h
- int 21h
- ;one other thing that you should do is save the "break" setting
- ;and turn it off, so key entries such as ctrl-c can't upset our isr.
- ;firstly, get the vectors...
- mov ax,351Bh
- int 21h
- mov oldoffivt1B,bx
- mov oldsegivt1B,es
- mov ax,3523h
- int 21h
- mov oldoffivt23,bx
- mov oldsegivt23,es
- mov ax,3524h
- int 21h
- mov oldoffivt24,bx
- mov oldsegivt24,es
- mov ax,3300h ;is ctrl-c checking turned on?
- int 21h ;dl=1 enabled
- mov oldctrlc,dl
- ;now hook them...
- mov ax,251Bh
- mov dx,OFFSET runtime1B
- int 21h
- mov ax,2523h
- mov dx,OFFSET runtime23
- int 21h
- mov ax,2524h
- mov dx,OFFSET runtime24
- int 21h
- mov ax,3301h ;ctrl-c testing
- xor dl,dl ;turned off.
- int 21h
-
- ;should also save extended error information (funcs 5D, 59)
- ; and the DTA (disk transfer area).
- ;Note that all of the above is reversed upon isr exit.
- ;
- ;a confirmation that we got this far!...
- call longbeep
-
- ;..............................................................
- ;this is it... this is where we do whatever the tsr is supposed to do...
- ;let's display a char on screen and wait for another key...
- ppp: mov ah,0 ;get char from key buffer.
- int 16h ;(goes to old vector, as isrbusy is set).
- cmp ax,2C00h
- je backtohost
- mov ah,9 ;display a char
- mov bl,70h ;attribute/colour
- mov bh,0 ;video page
- mov cx,1 ;just one char
- int 10h
- jmp ppp
-
- backtohost:
- ;.......
- exit4:
- mov ah,50h ;restore host psp
- mov bx,oldpspseg
- int 21h
- ;restore old break vectors & ctrl-c testing...
- push ds
- mov ax,251Bh
- lds dx,DWORD PTR cs:oldoffivt1B
- int 21h
- mov ax,2523h
- lds dx,DWORD PTR cs:oldoffivt23
- int 21h
- mov ax,2524h
- lds dx,DWORD PTR cs:oldoffivt24
- int 21h
- pop ds
- mov ax,3301h ;restore ctrl-c checking state.
- mov dl,oldctrlc
- int 21h
- ;......
- popa ;restore registers.
- pop ds ; /
- pop es ; /
- cli
- mov ss,cs:oldss ;restore host stack
- mov sp,cs:oldsp ; /
- mov cs:isrbusy,0 ;isr no longer in use
- mov cs:isrwanted,0 ;isr doesnt want to popup.
- exit: iret
- ;....................................................................
- runtime2F:
- ;also entered if try to reload this tsr... install sends AX=CC00
- ;if this signature, return with AX=CC01 to say already loaded...
- cmp ah,0CCh ;note can use this mechanism to send
- jne nextsig ; messages to the tsr from a dosapp:
- cmp al,0 ;is it an install test?(value in AL=0)
- je installtest
- iret
- installtest: mov al,1 ;flag can't load.
- jmp SHORT chain2F
- nextsig:
-
- ;entered when Windows loads, with AX=1605h, and when Windows unloads,
- ;with AX=1606h....
- ;detect when Windows loads, and set a flag ...
- sti ;documentation says this req'd.
- cmp ax,1605h ;test if Win is loading
- jne notload
- cmp cx,0 ;this must always be 0, else error.
- jne loaderror
- mov cs:winloaded,1
- mov cs:winmode,dl
- jmp SHORT chain2F
- notload: cmp ax,1606h ;test if Win is unloading.
- jne notunload
- mov cs:winloaded,0
- jmp SHORT chain2F
- notunload:
-
-
- loaderror:
- chain2F:
- jmp DWORD PTR cs:oldoffivt2F
- ;..................................................................
- runtime28:
- ;this isr is required because of the peculiar way COMMAND.COM works!
- pushf
- call DWORD PTR CS:oldoffivt28 ;call old int-28
- push ds
- push es
- pusha
- push cs
- pop ds
- ;is dos busy...
- les bx,DWORD PTR dosbusyoff
- mov al,es:[bx] ;get indos flag
- or al,al
- jz mmm ;if set, then we can popup.
- ;find out if isr wants to popup...
- cmp isrwanted,0
- jz mmm
- pushf
- call FAR PTR vvv ;calls runtime16 as an interrupt.
- mmm: popa
- pop es
- pop ds
- iret
- ;............................................................
- runtime24: xor al,al
- runtime1B:
- runtime23: iret
- ;................................................................
- longbeep:
- pusha
- mov al,0B6h ;turn on loudspeaker
- out 43h,al
- mov bx,07C5h
- mov al,bl
- out 42h,al
- mov al,bh
- out 42h,al
- in al,61h
- or al,3
- out 61h,al
- mov cx,0ffffh
- xxx: nop
- pusha ;just to kill time
- popa
- loop xxx
- in al,61h ;turn off loudspeaker
- and al,0FCh
- out 61h,al
- popa
- ret
- ;................................................................
- endprog: ;everything past here dumped when made resident.
- start:
-
- ;save ptr to psp...
- mov tsrpspseg,es ;if com, they all pt to it!
- ;is this tsr already installed?... i have given it a signature of CCh...
- mov ax,0CC00h ;AL=0 is install-test code for my 2F handler.
- int 2Fh ;multiplex interrupt (that we will hook)
- or al,al ;AL=non-0 means abort.
- jnz abortload
- ;get the addr of the dos-busy flag...
- mov ah,34h
- int 21h ;-->es:bx
- mov dosbusyoff,bx
- mov dosbusyseg,es
- ;
- ;hook int-2Fh vector in ivt. Windows calls this with AX=1605h when it loads,
- ;with regs telling useful info, such as if loading in Standard or
- ;Enhanced mode....
- mov ax,352Fh ;get int-2F vector in ivt.
- int 21h ; /
- mov oldoffivt2F,bx ;save it
- mov oldsegivt2F,es ; /
- mov ax,252Fh ;hook int-2F
- lea dx,runtime2F ;set ivt vector.
- int 21h ; /
- ;
- ;hook keypresses ...
- mov ax,3516h ;get int-16h vector in ivt.
- int 21h ; /
- mov oldoffivt16,bx ;save it
- mov oldsegivt16,es ; /
- mov ax,2516h ;hook int-16
- lea dx,runtime16 ;set ivt vector.
- int 21h ; /
- ;
- ;hook int-28h. COMMAND.COM calls this when idling & reading the keyboard...
- ;unfortunately when entering int-16 from COMMAND.COM, indos always set,
- ;but at int 28h call it is safe...
- mov ax,3528h
- int 21h
- mov oldoffivt28,bx
- mov oldsegivt28,es
- mov ax,2528h
- lea dx,runtime28
- int 21h
- ;
- ;free the environment block ... ###(this may upset int-2F/1687h)
- ; mov es,ds:[2Ch] ;pointer to seg. addr. of env. block
- ; mov ah,49h ;deallocate memory
- ; int 21h ; /
- ;
- lea dx,endprog+17 ;point past all code in this module.
- shr dx,4 ;compute # paragraphs to keep.
- mov ax,3100h ;terminate and stay resident.
- int 21h ; /
- abortload:
- call longbeep
- mov ax,4C00h ;don't make resident.
- int 21h
-
- ;...............................................................
- int16 ENDS
- END install
-
-
-